grammar Amuthu;

options
{
	output = AST;
	ASTLabelType = CommonTree;
}

tokens
{
   UNARY_MINUS;
}

@header {
package org.amuthu.parser;
}

@lexer::header {
package org.amuthu.parser;
}

expression
	:   logicalOrExpr
	;
	
parenthesisedExpr 
    :   LPAREN! expression RPAREN!
    ;
		
logicalOrExpr
	:	logicalAndExpr (OR^ logicalAndExpr)* ;

logicalAndExpr
	:	equalityExpr (AND^ equalityExpr)* ;

equalityExpr
	:	relationalExpr (( EQUALS^ | NOT_EQUALS^ ) relationalExpr )* ;

relationalExpr
    :   additiveExpr 
        (   (   LESSTHAN_EQ^
            |   GREATERTHAN_EQ^
            |   LESSTHAN^
            |   GREATERTHAN^
            )
            additiveExpr
        )*
    ;
 
additiveExpr
    :   multiplicativeExpr
        (   (   PLUS^
            |   MINUS^
            )
            multiplicativeExpr
        )*
    ;

multiplicativeExpr
    :   powerExpr 
        (   (   MULTIPLY^
            |   DIVIDE^
            |   MODULO^
            )
            powerExpr
        )*
    ;

powerExpr
	:	unaryExpr ( POWER^ unaryExpr )*
	;

unaryExpr
    :   PLUS unaryExpr ->  unaryExpr
    |   MINUS unaryExpr -> ^(UNARY_MINUS unaryExpr)
    |   NOT unaryExpr ->  ^(NOT unaryExpr)
    |   primaryExpr
    ;

primaryExpr
    :   parenthesisedExpr
    |	  literal
    ;
    
literal 
    :   INTEGER
    |   DOUBLE
    |   BOOLEAN
    |   QUOTE
    |   function
    ;
    
function 
	:	IDENTIFIER LPAREN ( expression (COMMA expression)* )? RPAREN -> ^(IDENTIFIER expression*);
    
//Lexer
LPAREN                  
	:	 '('               ;
RPAREN                  
	:	 ')'               ;
QUESTION                
	:	 '?'               ;
COMMA 
	:	',' ;
ASSIGN		:	'=';
OR 			: 	'or';
AND 			: 	'and';
EQUALS		:	'==';
NOT_EQUALS	:	'!=';
LESSTHAN		:	'<';
LESSTHAN_EQ	:	'<=';
GREATERTHAN	:	'>';
GREATERTHAN_EQ	:	'>=';
PLUS			:	'+';
MINUS			:	'-';
MULTIPLY			:	'*';
DIVIDE			:	'/';
MODULO			:	'%';
POWER			:	'^';
NOT	:	'!' | 'not';
BOOLEAN		:	'true' | 'false';
QUOTE       
	:	'open' | 'high' | 'low' | 'close' | 'volume';

INTEGER :	('0' | '1'..'9' '0'..'9'*);
DOUBLE	:	('0'..'9')+ '.' ('0'..'9')* | '.' ('0'..'9')+;
IDENTIFIER	:	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
WHITESPACE	:	( ' ' | '\t' | '\r' | '\n' ) { $channel = HIDDEN; };
    